package com.personal.dataanalyse.reportmanage.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.personal.core.data.DataColumn;
import com.personal.core.data.DataColumns;
import com.personal.core.data.DataRow;
import com.personal.core.data.DataTable;
import com.personal.core.port.HaveDeepAndChildren;
import com.personal.core.utils.Assert;
import com.personal.core.utils.CoreUtil;
import com.personal.core.utils.DeepChildrenUtil;
import com.personal.core.utils.ReGularUtil;
import com.personal.core.utils.StringUtil;
import com.personal.dataanalyse.consts.FieldConsts;
import com.personal.dataanalyse.enums.FieldDataTypeEnum;
import com.personal.dataanalyse.enums.ModelFieldTypeEnum;
import com.personal.dataanalyse.enums.XyTypeEnum;
import com.personal.dataanalyse.reportmanage.base.DataAnalyseModel;
import com.personal.dataanalyse.reportmanage.base.DimensionInfo;
import com.personal.dataanalyse.reportmanage.base.QuotaInfo;
import com.personal.dataanalyse.reportmanage.entity.DataColumnReportEx;
import com.personal.dataanalyse.reportmanage.entity.DataRowReportEx;
import com.personal.dataanalyse.reportmanage.entity.ReportHeader;
import com.personal.dataconvert.DataTable2Html;
import com.personal.dataconvert.bean.CombineColumnConfig;
import com.personal.dataconvert.bean.HeaderConfig;
import com.personal.dataconvert.bean.HtmlConfig;
import com.personal.dataconvert.util.ExcelHtmlUtil;

/**
 * 模型工具类
 * @author cuibo
 *
 */
public class ModelUtil
{
	private ModelUtil()
	{
	}
	
    /**
     * 获取维度的最大深度
     * @param groupFields
     * @return
     */
    public static int getMaxGroupFieldDeep(List<DimensionInfo> groupFields)
    {
        return DeepChildrenUtil.getMaxDeep(groupFields);
    }
    
    /**
     * 获取行列转换的Y维度的最大深度（只取有效深度）
     * @param groupFields
     * @return
     */
    public static int getTransRowColMaxYGroupFieldDeep(List<DimensionInfo> groupFields)
    {
        return getTransRowColMaxYGroupFieldDeepImpl(groupFields);
    }
    
    /**
     * 获取最大深度
     * @param groupFields
     * @param maxDeep  传-1
     * @return
     */
    private static int getTransRowColMaxYGroupFieldDeepImpl(List<DimensionInfo> dimensionInfos)
    {
        if (CoreUtil.isEmpty(dimensionInfos))
        {
            return 0;
        }
        int result = -1;
        for (DimensionInfo di : dimensionInfos)
        {
            if (di.getDeepLength() > result && di.hasCalOrCol())
            {
                result = di.getDeepLength();
            }
            // 子维度的深度跟定比上一级的维度深度大
            if (di.getChildren() != null && di.getChildren().size() > 0)
            {
                int tempResult = getTransRowColMaxYGroupFieldDeepImpl(di.getChildren());
                if (tempResult > result)
                {
                    result = tempResult;
                }
            }
        }
        return result;
    }

    /**
     * 获取指定深度下的所有维度
     * @param groupFields
     * @param deep
     * @return
     */
    public static List<DimensionInfo> getGroupFieldsByDeep(List<DimensionInfo> groupFields, int deep)
    {
        List<? extends HaveDeepAndChildren> tempResult = DeepChildrenUtil.getByDeep(groupFields, deep);
        if (tempResult == null || tempResult.isEmpty())
        {
            return null;
        }
        List<DimensionInfo> result = new ArrayList<DimensionInfo>();
        for (HaveDeepAndChildren haveDeepAndChildren : tempResult)
        {
            result.add((DimensionInfo) haveDeepAndChildren);
        }
        return result;
    }

    /**
     * 计算groupFields的深度
     * @param groupFields
     */
    public static void setDimensionInfoDeepLength(List<? extends DimensionInfo> groupFields)
    {
        DeepChildrenUtil.setDeepLength(groupFields);
    }

    /**
     * 获取条件里面的关系运算符
     * @param string
     * @return
     */
    public static String getRelationSplit(String singleCondition)
    {
        if (CoreUtil.isEmpty(singleCondition))
        {
            return null;
        }
        // 判断需要依据一定的顺序
        if (singleCondition.contains(FieldConsts.NE))
        {
            return FieldConsts.NE;
        } else if (singleCondition.contains(FieldConsts.GTEQ))
        {
            return FieldConsts.GTEQ;
        } else if (singleCondition.contains(FieldConsts.LTEQ))
        {
            return FieldConsts.LTEQ;
        } else if (singleCondition.contains(FieldConsts.EQ))
        {
            return FieldConsts.EQ;
        } else if (singleCondition.contains(FieldConsts.LT))
        {
            return FieldConsts.LT;
        } else if (singleCondition.contains(FieldConsts.GT))
        {
            return FieldConsts.GT;
        }
        return null;
    }

    /**
     * 检查FieldDataSql的合法性
     * @param fieldSql
     * @return
     */
    public static boolean checkLegalFieldDataSql(String fieldDataSql)
    {
        // 空不合法
        if (CoreUtil.isEmpty(fieldDataSql))
        {
            return false;
        }
        // 数字常量不合法
        return !CoreUtil.isNumber(fieldDataSql);
    }
    
    /**
     * 将规则报表DataTable转Html
     * @param table
     * 多表头分割符固定是：ExcelHtmlUtil.REPLACEPOINTFLAG
     * @param withTitle  是否填充标题
     * @return
     * @throws Exception 
     */
    public static String transRegularDataTable2html(DataTable table, boolean withTitle) throws Exception
    {
        return transRegularDataTable2html(table, (HtmlConfig)null, withTitle);
    }
    
    /**
     * 将规则报表DataTable转Html
     * @param table
     * 多表头分割符固定是：ExcelHtmlUtil.REPLACEPOINTFLAG
     * @return
     * @throws Exception 
     */
    public static String transRegularDataTable2html(DataTable table) throws Exception
    {
        return transRegularDataTable2html(table, null);
    }


    /**
     * 将规则报表DataTable转Html
     * @param table
     * @param htmlConfig 可以为空,为null 时自动构建
     * 多表头分割符固定是：ExcelHtmlUtil.REPLACEPOINTFLAG
     * @return
     * @throws Exception 
     */
    public static String transRegularDataTable2html(DataTable table, HtmlConfig htmlConfig) throws Exception
    {
        return transRegularDataTable2html(table, htmlConfig, true);
    }
    
    /**
     * 将规则报表DataTable转Html
     * @param table
     * @param htmlConfig 可以为空,为null 时自动构建
     * 多表头分割符固定是：ExcelHtmlUtil.REPLACEPOINTFLAG
     * @param withTitle  是否填充标题
     * @return
     * @throws Exception 
     */
    public static String transRegularDataTable2html(DataTable table, HtmlConfig htmlConfig, boolean withTitle) throws Exception
    {
        if (table == null)
        {
            return "";
        }
        // 计算合并配置
        Set<CombineColumnConfig> combineColumnConfigs = calRegularCombineConfigs(table);
        if (htmlConfig != null)
        {
            htmlConfig.setWithTitle(withTitle);
        }
        return new DataTable2Html.Builder().setCombineColumnConfigs(combineColumnConfigs).setHtmlConfig(htmlConfig).setWithTitle(withTitle)
                .setDataTable(table).setSplitFlag(ExcelHtmlUtil.REPLACEPOINTFLAG).build().createHtml();
    }
    
    /**
     * 将规则报表DataTable转Html
     * @param table
     * @param combineColumnConfigs
     * @param withTitle  是否填充标题
     * @return
     * @throws Exception 
     */
    public static String transRegularDataTable2html(DataTable table, Set<CombineColumnConfig> combineColumnConfigs, boolean withTitle) throws Exception
    {
        if (table == null)
        {
            return "";
        }
        return new DataTable2Html.Builder().setCombineColumnConfigs(combineColumnConfigs).setWithTitle(withTitle)
                .setDataTable(table).setSplitFlag(ExcelHtmlUtil.REPLACEPOINTFLAG).build().createHtml();
    }
    
    /**
     * 将规则报表DataTable转Html(只有表头部分)
     * @param table
     * @param htmlConfig 可以为空为null 时自动构建
     * 多表头分割符固定是：ExcelHtmlUtil.REPLACEPOINTFLAG
     * @return
     * @throws Exception 
     */
    public static String transRegularDataTable2htmlheader(DataTable table, HtmlConfig htmlConfig) throws Exception
    {
        if (table == null)
        {
            return "";
        }
        // 计算合并配置
        Set<CombineColumnConfig> combineColumnConfigs = null;
        if (htmlConfig == null)
        {
            combineColumnConfigs = calRegularCombineConfigs(table);
        }
        return new DataTable2Html.Builder().setCombineColumnConfigs(combineColumnConfigs).setHtmlConfig(htmlConfig)
                .setDataTable(table).setSplitFlag(ExcelHtmlUtil.REPLACEPOINTFLAG).build().createHeader();
    }

    /**
     * 计算DataTable合并配置
     * @param table
     * @return
     */
    public static Set<CombineColumnConfig> calRegularCombineConfigs(DataTable table)
    {
        if (table == null || table.getColumns() == null)
        {
            return null;
        }
        Set<CombineColumnConfig> result = new HashSet<CombineColumnConfig>();
        DataColumnReportEx columnEx = null;
        for (DataColumn dataColumn : table.getColumns())
        {
            if (!(dataColumn instanceof DataColumnReportEx))
            {
                continue;
            }
            columnEx = (DataColumnReportEx) dataColumn;
            result.addAll(columnEx.getCombineConfigs());
        }
        return result;
    }

    /**
     * 设置小数位
     * @param table
     * @param isTransRowCol  是否是行列转换DataTable  是：小数位信息在行上，不是：小数位信息在列上
     */
    public static void setDotNum(DataTable table, boolean isTransRowCol)
    {
        if (!CoreUtil.checkDataTableHasData(table))
        {
            return;
        }
        // 行列转换DataTable的小数位信息在行上
        if (isTransRowCol)
        {
        	setColDotNum(table);
        } else
        {
        	setRowDotNum(table);
        }
    }
    
    /**
     * 设置列小数
     * @param table
     */
    private static void setColDotNum(DataTable table)
    {
    	DataRowReportEx rowEx = null;
        for (DataRow row : table.getRows())
        {
            if (!(row instanceof DataRowReportEx))
            {
                continue;
            }
            rowEx = (DataRowReportEx) row;
            if (!FieldDataTypeEnum.数值.toString().equals(rowEx.getDataType()))
            {
                continue;
            }
            for (DataColumn column : table.getColumns())
            {
                DataColumnReportEx columnEx = (DataColumnReportEx) column;
                if (columnEx.isOtherGroupCol())
                {
                    continue;
                }
                row.setValue(column, CoreUtil.parseDblStr(row.getItemMap().get(column.getColumnName()), rowEx.getDotNum(), true));
            }
        }
    }
    
    
    /**
     * 设置行小数
     * @param table
     */
    private static void setRowDotNum(DataTable table)
    {
    	// 非行列转换DataTable 的小数位信息在列上
        DataColumnReportEx colEx = null;
        for (DataColumn col : table.getColumns())
        {
            if (!(col instanceof DataColumnReportEx))
            {
                continue;
            }
            colEx = (DataColumnReportEx) col;
            if (FieldDataTypeEnum.数值.toString().equals(colEx.getDataType()))
            {
                for (DataRow row : table.getRows())
                {
                    row.setValue(col, CoreUtil.parseDblStr(row.getItemMap().get(col.getColumnName()), colEx.getDotNum(), true));
                }
            }
        }
    }    
    

    /**
     * 给维度设置Xy类别
     * @param dimensionInfos
     * @param xy
     */
    public static void setDimensionXyInfo(List<DimensionInfo> dimensionInfos, XyTypeEnum xy)
    {
        if (dimensionInfos == null || dimensionInfos.isEmpty())
        {
            return;
        }
        for (DimensionInfo dimensionInfo : dimensionInfos)
        {
            dimensionInfo.setXy(xy);
        }
    }

    /**
     * 计算纵向合并配置
     * @param headerConfigs  已经生成的表头配置
     */
    public static Set<CombineColumnConfig> calZxCombineConfigs(List<ReportHeader> headerConfigs)
    {
        if (headerConfigs == null || headerConfigs.isEmpty())
        {
            return null;
        }
        // 计算纵向合并：headerConfig的深度-1即列数，
        // 先获取HeaderConfig的最大深度，每一层深度都对应表格的没一列
        int maxDeep = ExcelHtmlUtil.getMaxDeepFromTrees(headerConfigs);
        // 每层深度已经遍历到的行号
        Map<Integer, Integer> rowIndexMap = new HashMap<Integer, Integer>();
        for (int i = 0; i < maxDeep; i++)
        {
            rowIndexMap.put(i, 0);
        }
        // 纵向合并配置
        Set<CombineColumnConfig> result = new HashSet<CombineColumnConfig>();
        for (HeaderConfig headerConfig : headerConfigs)
        {
            calAndAddZxCombineConfigsImpl(headerConfig, result, rowIndexMap, maxDeep);
        }
        return result;
    }

    private static void calAndAddZxCombineConfigsImpl(HeaderConfig headerConfig, Set<CombineColumnConfig> result,
            Map<Integer, Integer> rowIndexMap, int maxDeep)
    {
        if (headerConfig == null)
        {
            return;
        }
        // 叶子节点
        List<? extends HeaderConfig> leafs = headerConfig.getLeafHeader();
        if (leafs == null || leafs.isEmpty())
        {
            // 如果没有了叶子，则需要把当前深度遍历到的行号加1
            rowIndexMap.put(headerConfig.getDeepLength() - 1, rowIndexMap.get(headerConfig.getDeepLength() - 1) + 1);
            // 如果深度小于最大深度，则需要把后面列都加1
            if (headerConfig.getDeepLength() < maxDeep)
            {
                for (int i = headerConfig.getDeepLength(); i < maxDeep; i++)
                {
                    rowIndexMap.put(i, rowIndexMap.get(i) + 1);
                }
            }
        } else
        {
            // 添加纵向合并
            CombineColumnConfig combineConfig = new CombineColumnConfig(headerConfig.getDeepLength() - 1,
                    CombineColumnConfig.纵向合并);
            combineConfig.setMinRowScope(rowIndexMap.get(headerConfig.getDeepLength() - 1));
            combineConfig.setMaxRowScope(combineConfig.getMinRowScope() + leafs.size());
            result.add(combineConfig);
            // 当前深度遍历到的行号加leafs.size()
            rowIndexMap.put(headerConfig.getDeepLength() - 1,
                    rowIndexMap.get(headerConfig.getDeepLength() - 1) + leafs.size());
        }
        // 递归
        if (headerConfig.getChildren().isEmpty())
        {
            return;
        }
        for (HeaderConfig child : headerConfig.getChildren())
        {
            calAndAddZxCombineConfigsImpl(child, result, rowIndexMap, maxDeep);
        }
    }

    /**
     * 移除不是指标列的头部
     * @param headerConfigs
     */
    public static void removeIsNotTargetHeaderConfig(List<? extends HeaderConfig> headerConfigs)
    {
        if (headerConfigs == null || headerConfigs.isEmpty())
        {
            return;
        }
        for (Iterator<? extends HeaderConfig> iterator = headerConfigs.iterator(); iterator.hasNext();)
        {
            HeaderConfig headerConfig = iterator.next();
            if (!(headerConfig instanceof ReportHeader))
            {
                continue;
            }
            ReportHeader reportHeader = (ReportHeader) headerConfig;
            if (!ModelFieldTypeEnum.isCommonOrCalOrGroupField(reportHeader.getFieldType()))
            {
                if (!reportHeader.hasQuotaHeader())
                {
                    iterator.remove();
                }
            }
            // 递归处理子节点
            if (reportHeader.getChildren() != null && !reportHeader.getChildren().isEmpty())
            {
                removeIsNotTargetHeaderConfig(reportHeader.getChildren());
            }
        }
    }

    /**
     * 从childrenTemp中查找比showOrder小的数据，并移除查找结果
     * @param childrenTemp
     * @param showOrder
     * @return
     */
    public static List<DimensionInfo> lookChildrenBefore(List<DimensionInfo> childrenTemp, long showOrder)
    {
        if (childrenTemp == null || childrenTemp.isEmpty())
        {
            return null;
        }
        List<DimensionInfo> result = new ArrayList<DimensionInfo>();
        for (Iterator<DimensionInfo> iterator = childrenTemp.iterator(); iterator.hasNext();)
        {
            DimensionInfo dimensionInfo = iterator.next();
            if (dimensionInfo.getFieldOrder() < showOrder)
            {
                result.add(dimensionInfo);
                // 移除
                iterator.remove();
            }
            
        }
        return result;
    }
    
    /**
     * 重新计算计算列的fieldDataSql
     * @param model
     * @param parentColumnLabel
     * @param result
     * @param calColumn
     * @throws Exception 
     */
    public static void handleCalColumnFieldSql(DataAnalyseModel model, String parentColumnLabel, DataColumns result, DataColumnReportEx calColumn) throws Exception
    {
        String dataSql = calColumn.getFieldDataSql();
        String parentColumnLabelWithFlag = CoreUtil.isEmpty(parentColumnLabel) ? "" : parentColumnLabel + ExcelHtmlUtil.REPLACEPOINTFLAG;
        String message = CoreUtil.isEmpty(parentColumnLabel) ? "模型" : parentColumnLabel;
        String[] arr = ReGularUtil.EXPANDKHPATTERNANDABS.split(dataSql);
        Assert.isNotNullOrEmpty(arr,"ID为：" + model.getId() + "：名称为：" + model.getModelName() + "下的" + message + "下的" + dataSql + "计算列不合法！");
        for (String string : arr)
        {
            if (CoreUtil.isEmpty(string))
            {
				continue;
			}
            // 表达式中可以出现常量
            if (!ModelUtil.checkLegalFieldDataSql(string))
            {
                continue;
            }
            // 通过parentColumnName + string 去 result中查找对应的列
            DataColumnReportEx lookCol = ModelUtil.lookDataColumnByLabel(parentColumnLabelWithFlag + string, result);
            Assert.isNotNull(lookCol, "在ID为：" + model.getId() + "：名称为：" + model.getModelName() + "下的" + message + "下没有查找到" + string + "列！");
            calColumn.getCalColumns().add(lookCol);
            dataSql = StringUtil.replaceFirst(dataSql, string, lookCol.getColumnName());
        }
        calColumn.setFieldDataSql(dataSql);
    }
    
    /**
     * 通过columnLabel在result中查找对应的DataColumn
     * @param columnLabel
     * @param result
     * @return
     */
    public static DataColumnReportEx lookDataColumnByLabel(String columnLabel, DataColumns result)
    {
        if (result == null || result.isEmpty())
        {
            return null;
        }
        for (DataColumn dataColumn : result)
        {
            if (CoreUtil.checkEqualIgnoreSpace(columnLabel, dataColumn.getColumnLable()))
            {
                return (DataColumnReportEx)dataColumn;
            }
        }
        return null;
    }
    
    /**
     * 给分析因子设置model
     * @param tempModel
     */
    public static void setModel(DataAnalyseModel tempModel)
    {
        if (tempModel == null)
        {
            return;
        }
        // 计算列
        if (tempModel.getCalFields() != null)
        {
            for (QuotaInfo quotaInfo : tempModel.getCalFields())
            {
                quotaInfo.setModel(tempModel);
            }
        }
        // 指标列
        if (tempModel.getColumnFields() != null)
        {
            for (QuotaInfo quotaInfo : tempModel.getColumnFields())
            {
                quotaInfo.setModel(tempModel);
            }
        }
        // 维度
        if (tempModel.getxGroupFields() != null)
        {
            for (DimensionInfo dimensionInfo : tempModel.getxGroupFields())
            {
                dimensionInfo.setModel(tempModel, true);
            }
        }
        if (tempModel.getyGroupFields() != null)
        {
            for (DimensionInfo dimensionInfo : tempModel.getyGroupFields())
            {
                dimensionInfo.setModel(tempModel, true);
            }
        }
    }

    
    /**
     * 包HeaderConfig的单位加到表头
     * @param headerConfigs
     */
    public static void addHeaderConfigUnit(List<ReportHeader> headerConfigs)
    {
        if (CoreUtil.isEmpty(headerConfigs))
        {
            return;
        }
        for (ReportHeader headerConfig : headerConfigs)
        {
            if (!CoreUtil.isEmpty(headerConfig.getFieldUnit()) && headerConfig.isHeaderAddUnit())
            {
                if (headerConfig.isLeaf())
                {
                    headerConfig.setDisplayName(headerConfig.getDisplayName() + "（" + headerConfig.getFieldUnit() + "）");
                } else
                {
                    headerConfig.setDisplayName(headerConfig.getDisplayName() + headerConfig.getFieldUnit());
                }
            }
            if (!headerConfig.isLeaf())
            {
                addHeaderConfigUnit(getChildrenAsReportHeader(headerConfig));
            }
        }
    }
    
    private static List<ReportHeader> getChildrenAsReportHeader(ReportHeader reportHeader)
    {
        if (reportHeader.isLeaf())
        {
            return null;
        }
        List<ReportHeader> result = new ArrayList<ReportHeader>();
        for (HeaderConfig config : reportHeader.getChildren())
        {
            result.add((ReportHeader)config);
        }
        return result;
    }

    /**
     * 需要给指标列的行数据加上单位
     * @param result
     */
    public static void addTargetColUnit(DataTable result)
    {
        // 指标列
        DataColumnReportEx columnReportEx = null;
        for (DataColumn column : result.getColumns())
        {
            DataColumnReportEx local = (DataColumnReportEx) column;
            if (FieldConsts.TARGET_CSS.equals(local.getStyleClass()))
            {
                columnReportEx = local;
                break;
            }
        }
        if (columnReportEx == null)
        {
            return;
        }
        for (DataRow row : result.getRows())
        {
            DataRowReportEx rowEx = (DataRowReportEx) row;
            String unit = rowEx.getColumnReportEx().getHeaderConfig().getFieldUnit();
            if (!CoreUtil.isEmpty(unit))
            {
                rowEx.setValue(columnReportEx, CoreUtil.parseStr(row.getValue(columnReportEx)) + "（" + unit + "）");
            }
            
        }
    }
    
}
